package wstm;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.transaction.Status;

import wsresource.client.WSResourceManager;

public class WSTransaction  {
  public String myXid = null;
  private List<WSResourceManager> enlistedWSRes;
  public int status;

  public WSTransaction(){
    enlistedWSRes = new ArrayList<wsresource.client.WSResourceManager>();
    status = Status.STATUS_UNKNOWN;
  }

  /**
   * Complete the transaction represented by this WSTransaction object.
   * @return true if the transaction ends successfully false if don't.
   */
  public boolean commit(){
    System.out.println("Transaction " + myXid  + " commit begin" );
    Iterator<wsresource.client.WSResourceManager> it = enlistedWSRes.iterator();
    if(enlistedWSRes.size() == 1){
      //Commit one phase
      status = Status.STATUS_COMMITTING;
      System.out.println("Begin one phase commit" );
      wsresource.client.WSResourceManager res = it.next();
      if(!res.commit(myXid, true)){
        System.err.println("WSResource cannot commit"  );
        return false;
      }
      return true;
    }
    System.out.println("Begin two phase commit" );
    //Prepare all enlisted resources
    System.out.println("Phase 1" );
    while (it.hasNext()) {
      status = Status.STATUS_PREPARING;
      wsresource.client.WSResourceManager res = it.next(); 
      System.out.println("Try prepare resource id: "+ res);
      int vote = res.prepare(myXid);
      if(vote != 0){ 
        System.err.println("WSResource id: " +res+ " not prepared"  );
        return false;
      }
    }
    status = Status.STATUS_PREPARED;
    //All resources prepared, commit
    System.out.println("Phase 2" );
    Iterator<wsresource.client.WSResourceManager> it2 = enlistedWSRes.iterator();
    while (it2.hasNext()) {
      status = Status.STATUS_COMMITTING;
      wsresource.client.WSResourceManager res = it2.next();
      System.out.println("Try commit resource:" + res);
      if(!res.commit(myXid, false)){
        System.err.println("WSResource "+res+" cannot commit"  );
        return false;
      }
    }
    System.out.println("All WSresource commited"  );
    status = Status.STATUS_NO_TRANSACTION;
    return true;
  } 

  /**
   * Disassociate the resource specified in wsRes from the transaction 
   * associated with this Transaction object.
   * @param wsRes
   * @param flag
   * @return true if the resource is delisted, false if don't
   */
  public boolean delistResource(wsresource.client.WSResourceManager wsRes, int flag){
    wsRes.end(myXid, 0); //Ojo con las flags
    System.out.println("Delist resource "+ wsRes  );
    if(enlistedWSRes.remove(wsRes)){
      return true;
    }
    return false;
  } 
  /**
   * Associate the resource specified in wsRes in the transaction 
   * associated with this Transaction object.
   * @param wsRes
   * @return true if the resource is enlisted, false if don't
   */
  public boolean enlistResource(wsresource.client.WSResourceManager wsRes){
    System.out.println("Try Enlist WSResource");
    wsRes.start(myXid, 0); //Ojo con las flags
    if(enlistedWSRes.add(wsRes)){
      System.out.println("WSResource Enlisted ");
      return true;
    }
    System.err.println("WSResource Cannot be Enlisted ");
    return false;
  } 
  /**
   * Rollback the transaction represented by this transaction object.
   */
  public void rollback(){
    Iterator<wsresource.client.WSResourceManager> it = enlistedWSRes.iterator();
    while (it.hasNext()) {
      status = Status.STATUS_ROLLING_BACK;
      wsresource.client.WSResourceManager res = it.next(); 
      System.out.println("Try prepare resource :"+res);
      res.rollback(myXid);
      delistResource(res,0);
    }
    status = Status.STATUS_NO_TRANSACTION;
  } 
  /**
   * Modify the transaction associated with the target object such that the
     * only possible outcome of the transaction is to roll back the transaction.
   */
  public void setRollbackOnly() {
    status = Status.STATUS_MARKED_ROLLBACK;
  }
  /**
   * Chech if the resources is allredy enlisted in the transaction asociated
   * with this object
   * @param wsRes true if the resource is alredy enlisted. false if don't
   */
  public boolean isEnlisted(wsresource.client.WSResourceManager wsRes){
    if(enlistedWSRes.contains(wsRes)){
      return true;
    }
    else{
      return false;
    }
  }
}
